namespace System.DataStructures
{
	/// <summary>
	/// Class defines functions of BitCounter
	/// </summary>
	internal static class BitCounter
	{
		private static readonly uint[] Masks32 = { 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF };
		private static readonly ulong[] Masks64 = { 0x5555555555555555, 0x3333333333333333, 0x0F0F0F0F0F0F0F0F, 0x00FF00FF00FF00FF, 0x0000FFFF0000FFFF, 0x00000000FFFFFFFF };

		/// <summary>
		/// Counts the bits in data of type <c>sbyte</c>.
		/// </summary>
		/// <param name="data">The data.</param>
		/// <returns>number of bits in the data</returns>
		public static int CountBits(sbyte data)
		{
			return CountBits((byte)data);
		}

		/// <summary>
		/// Counts the bits in data of type byte.
		/// </summary>
		/// <param name="data">The data.</param>
		/// <returns>number of bits in the data</returns>
		public static int CountBits(byte data)
		{
			for (int i = 0; i < 3; i++)
			{
				data = (byte)((data & Masks32[i]) + ((data >> (1 << i)) & Masks32[i]));
			}
			return data;
		}

		/// <summary>
		/// Counts the bits in data of type char.
		/// </summary>
		/// <param name="data">The data.</param>
		/// <returns>number of bits in the data</returns>
		public static int CountBits(char data)
		{
			return CountBits((ushort)data);
		}

		/// <summary>
		/// Counts the bits in data of type short.
		/// </summary>
		/// <param name="data">The data.</param>
		/// <returns>number of bits in the data</returns>
		public static int CountBits(short data)
		{
			return CountBits((ushort)data);
		}

		/// <summary>
		/// Counts the bits in data of type <c>ushort</c>.
		/// </summary>
		/// <param name="data">The data.</param>
		/// <returns>number of bits in the data</returns>
		public static int CountBits(ushort data)
		{
			for (int i = 0; i < 4; i++)
			{
				data = (ushort)((data & Masks32[i]) + ((data >> (1 << i)) & Masks32[i]));
			}
			return data;
		}

		/// <summary>
		/// Counts the bits in data of type int.
		/// </summary>
		/// <param name="data">The data.</param>
		/// <returns>number of bits in the data</returns>
		public static int CountBits(int data)
		{
			return CountBits((uint)data);
		}

		/// <summary>
		/// Counts the bits in data of type <c>uint</c>.
		/// </summary>
		/// <param name="data">The data.</param>
		/// <returns>number of bits in the data</returns>
		public static int CountBits(uint data)
		{
			for (int i = 0; i < 5; i++)
			{
				data = (data & Masks32[i]) + ((data >> (1 << i)) & Masks32[i]);
			}
			return (int)data;
		}

		/// <summary>
		/// Counts the bits in data of type long.
		/// </summary>
		/// <param name="data">The data.</param>
		/// <returns>number of bits in the data</returns>
		public static int CountBits(long data)
		{
			return CountBits((ulong)data);
		}

		/// <summary>
		/// Counts the bits in data of type <c>ulong</c>.
		/// </summary>
		/// <param name="data">The data.</param>
		/// <returns>number of bits in the data</returns>
		public static int CountBits(ulong data)
		{
			for (int i = 0; i < 6; i++)
			{
				data = (data & Masks64[i]) + ((data >> (1 << i)) & Masks64[i]);
			}
			return (int)data;
		}
	}
}